package com.daJiao.aspect;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.daJiao.exception.BusinessException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>Title:      LogAspect. </p>
 * <p>Description aop统一日志输出 </p>
 * <p>Copyright: Copyright (c) 2016</p>
 * <p>Company:    医百科技有限公司 </p>
 *
 * @author         <a href="yangwensheng@100doc.com.cn"/>杨文生</a>
 * @since      2021/4/22 19:44
 */
@Aspect
@Component
@Order(2)
public class LogAspect {
    private final static Logger logger = LoggerFactory.getLogger(LogAspect.class);
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    private static final ThreadLocal<Long> startTime = new ThreadLocal<>();
    private static final ThreadLocal<StringBuilder> sb = new ThreadLocal<>();

    @Pointcut("execution(public * com.wx.controller..*.*(..))")
    public void log() {

    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        StringBuilder builder = new StringBuilder();
        startTime.set(System.currentTimeMillis());
        sb.set(builder);
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        builder.append(LINE_SEPARATOR).append("--------------------begin------------------------").append(LINE_SEPARATOR);
        builder.append("[url         ]: " + request.getRequestURL().toString()).append(LINE_SEPARATOR);
        builder.append("[request     ]: " + request.getMethod()).append(LINE_SEPARATOR);
        builder.append("[class method]: " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()).append(LINE_SEPARATOR);
        builder.append("[locale      ]: " + request.getLocale().toString()).append(LINE_SEPARATOR);
        builder.append("[args        ]: " + Arrays.toString(joinPoint.getArgs())).append(LINE_SEPARATOR);
        builder.append("[header      ]: " + JSONObject.toJSONString(getHeadersInfo(request))).append(LINE_SEPARATOR);
    }


    @AfterReturning(pointcut = "log()", returning = "ret")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
        StringBuilder builder = sb.get();
        builder.append("[response    ]: " + JSON.toJSONString(ret)).append(LINE_SEPARATOR);
        builder.append("[time        ]: " + (System.currentTimeMillis() - startTime.get()) + "ms").append(LINE_SEPARATOR);
        builder.append("---------------------end-----------------------").append(LINE_SEPARATOR);
        logger.info(builder.toString());
    }

    @AfterThrowing(pointcut = "log()", throwing = "exp")
    public void doAfterThrowing(JoinPoint joinPoint, Exception exp) throws Throwable {
        // 处理完请求，返回内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        StringBuilder builder = new StringBuilder();
        // 记录下请求内容
        builder.append(LINE_SEPARATOR).append("--------------------begin------------------------").append(LINE_SEPARATOR);
        builder.append("[url         ]: " + request.getRequestURL().toString()).append(LINE_SEPARATOR);
        builder.append("[request     ]: " + request.getMethod()).append(LINE_SEPARATOR);
        builder.append("[args        ]: " + Arrays.toString(joinPoint.getArgs())).append(LINE_SEPARATOR);
        builder.append("[locale      ]: " + request.getLocale().toString()).append(LINE_SEPARATOR);
        builder.append("[exception   ]: " + ExceptionUtils.getStackTrace(exp)).append(LINE_SEPARATOR);
        builder.append("[time        ]: " + (System.currentTimeMillis() - startTime.get()) + "ms").append(LINE_SEPARATOR);
        builder.append("---------------------end-----------------------").append(LINE_SEPARATOR);

        if (exp instanceof BusinessException) {
            logger.warn(builder.toString());
        } else {
            logger.error(builder.toString());
        }
    }

    private Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> map = new HashMap<>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }
}